﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using System.Windows;
using System.Windows.Browser;
using System.Windows.Controls;
using UserRegistration.RegSvc;

namespace UserRegistration
{
	public partial class MainPage
	{
		private readonly RegistrationServiceClient _client;

		private readonly List<string> _states = new List<string>
		{
			"Step0",
			//0
			"Step1",
			//1
			"Step1LoadVerification",
			//2
			"Step1Verification",
			//3
			"Step1Verified",
			//4
			"Step2",
			//5
			"Step3",
			//6
			"Step3Verification",
			//7
			"Step3Verified",
			//8
			"Step3VerifyFailed",
			//9
			"Step4",
			//10
			"Step4Complete" //11
		};

		private string _agentname;

		private int _currentState;
		private string _password;
		private ulong _regId;

		public MainPage()
		{
			InitializeComponent();
			_client = new RegistrationServiceClient();
			if (App.RegId != 0 && App.OpCode == 31331 && !string.IsNullOrEmpty(App.PaypalToken) &&
			    !string.IsNullOrEmpty(App.PaypalPayerId))
			{
				_currentState = 7;
				SwitchState();
				_regId = App.RegId;
				_client.PaypalConfirmationCompleted += ClientPaypalConfirmationCompleted;
				_client.PaypalConfirmationAsync(App.RegId, App.PaypalToken, App.PaypalPayerId);
			}
			if (App.RegId != 0 && App.OpCode == 31330 && !string.IsNullOrEmpty(App.PaypalToken))
			{
				_currentState = 9;
				SwitchState();
				_regId = App.RegId;
			}
			SwitchState();
		}

		private void BtnBackClick(object sender, RoutedEventArgs e)
		{
			if (_currentState == 0)
				return;

			if (_currentState == 3) //enter email confirmation code screen
				_currentState = 1;

			else if (_currentState == 9)
				_currentState = 6;

			else
				_currentState--;

			SwitchState();
		}

		private void BtnNextClick(object sender, RoutedEventArgs e)
		{
			if (_currentState == _states.Count - 1)
				return;
			if (_currentState == 5) //agent name + password
			{
				txtAgentName.IsEnabled = false;
				txtPasswordInput1.IsEnabled = false;
				txtPasswordInput2.IsEnabled = false;
				_agentname = txtAgentName.Text;
				_password = txtPasswordInput1.Password;
				_client.SaveAgentNameAndPasswordCompleted += ClientSaveAgentNameAndPasswordCompleted;
				ulong corpId = ((Corporation) cmbCorporations.SelectedItem).Id;
				_client.SaveAgentNameAndPasswordAsync(_regId, _agentname, _password.EncryptPassword(), corpId);
				return;
			}
			if (_currentState == 6)
			{
				_client.SubmitPaymentDataCompleted += ClientSubmitPaymentDataCompleted;
				RegisteredUser ru = new RegisteredUser();
				ru.PaypalEmail = txtPaypalEmail.Text;
				_client.SubmitPaymentDataAsync(_regId, ru);
				_currentState++;
				SwitchState();
				return;
			}
			if (_currentState == 8)
			{
				HtmlPage.Window.Navigate(new Uri("http://localhost:81/Client.aspx"));
				return;
			}
			_currentState++;
			SwitchState();
		}

		private void ClientSubmitPaymentDataCompleted(object sender, SubmitPaymentDataCompletedEventArgs e)
		{
			_client.SubmitPaymentDataCompleted += ClientSubmitPaymentDataCompleted;
			if (!string.IsNullOrEmpty(e.Result))
			{
				string url = @"https://www.sandbox.paypal.com/cgi-bin/webscr?cmd=_express-checkout&token=" + e.Result;
				HtmlPage.Window.Navigate(new Uri(url));
			}
			else
				MessageBox.Show("Error communicating with paypal. The server returned an empty result.");
		}

		private void ClientPaypalConfirmationCompleted(object sender, PaypalConfirmationCompletedEventArgs e)
		{
			if (e.Result)
			{
				_currentState = 8;
				SwitchState();
				//WebClient wclient = new WebClient();
				//wclient.OpenReadCompleted += wclient_OpenReadCompleted;
				//wclient.DownloadProgressChanged += wclient_DownloadProgressChanged;
				//wclient.OpenReadAsync(new Uri("http://localhost:81/ClientBin/TheGameClient.xap"));
			}
		}

		private void SwitchState()
		{
			VisualStateManager.GoToState(this, _states[_currentState], false);
		}

		private void SwitchState(string stateName)
		{
			_currentState = _states.IndexOf(stateName);
			SwitchState();
		}

		#region Step 1 Email

		private void BtnVerifyEmailClick(object sender, RoutedEventArgs e)
		{
			_client.RequestEmailConfirmCodeCompleted += ClientRequestEmailConfirmCodeCompleted;
			Regex emailRegex =
				new Regex(@"\A(?<user>[a-zA-Z0-9]+(?:\.[a-zA-Z0-9]+)*)@(?<domain>[a-zA-Z0-9_-]+(?:\.[a-zA-Z0-9_-]+)+)\Z");
			if (!emailRegex.IsMatch(txtEmailAddressInput.Text))
			{
				MessageBox.Show(
					"The email address you entered is not of the correct format.\nOnly letters, numbers and points are allowed before @,\nonly letters, numbers, points and _, - are allowed for domain names.");
				return;
			}
			_client.RequestEmailConfirmCodeAsync(txtEmailAddressInput.Text);
			SwitchState("Step1LoadVerification");
		}

		private void ClientRequestEmailConfirmCodeCompleted(object sender, RequestEmailConfirmCodeCompletedEventArgs e)
		{
			_client.RequestEmailConfirmCodeCompleted -= ClientRequestEmailConfirmCodeCompleted;
			if (e.Result)
				SwitchState("Step1Verification");
			else
			{
				if (e.Error != null)
				{
				}
				MessageBox.Show(
					"An error was encountered while trying to send the confirmation mail.\nReasons:\n- The email you entered is already in use.\n- The server is offline. In this case, please try again later.\n");
				SwitchState("Step1");
			}
			_client.GetAvailableCorporationsCompleted += ClientGetAvailableCorporationsCompleted;
			_client.GetAvailableCorporationsAsync();
		}

		private void BtnConfirmEmailVerificationCodeClick(object sender, RoutedEventArgs e)
		{
			_client.VerifyEmailAddressCodeCompleted += ClientVerifyEmailAddressCodeCompleted;
			_client.VerifyEmailAddressCodeAsync(txtVerificationCodeInput.Text);
		}

		private void ClientVerifyEmailAddressCodeCompleted(object sender, VerifyEmailAddressCodeCompletedEventArgs e)
		{
			if (e.Result == 0)
			{
				MessageBox.Show("You entered a wrong confirmation code. It was rejected by the server. Please try again.");
				SwitchState("Step1");
			}
			else
			{
				_regId = e.Result;
				SwitchState("Step1Verified");
			}
		}

		private void ClientGetAvailableCorporationsCompleted(object sender, GetAvailableCorporationsCompletedEventArgs e)
		{
			_client.GetAvailableCorporationsCompleted -= ClientGetAvailableCorporationsCompleted;
			if (e.Error != null)
				return;
			cmbCorporations.ItemsSource = e.Result;
			cmbCorporations.SelectedItem = e.Result.Where(it => it.IsDefault).FirstOrDefault();
		}

		private void TxtEmailAddressInputGotFocus(object sender, RoutedEventArgs e)
		{
			txtEmailAddressInput.SelectAll();
		}

		#endregion

		#region Step 2 Agent name / password

		private bool _agentNameOk;

		private void BtnCheckAgentNameClick(object sender, RoutedEventArgs e)
		{
			Regex nameRegex = new Regex(@"\A(?:[a-zA-Z0-9\s]{4,32})\Z");
			if (nameRegex.IsMatch(txtAgentName.Text))
			{
				_client.CheckAgentNameCompleted += ClientCheckAgentNameCompleted;
				_client.CheckAgentNameAsync(txtAgentName.Text);
			}
			else
			{
				txtNameOk.Visibility = Visibility.Collapsed;
				txtNameNotOk.Visibility = Visibility.Visible;
			}
		}

		private void ClientCheckAgentNameCompleted(object sender, CheckAgentNameCompletedEventArgs e)
		{
			_client.CheckAgentNameCompleted -= ClientCheckAgentNameCompleted;
			if (e.Result)
			{
				_agentNameOk = true;
				txtNameOk.Visibility = Visibility.Visible;
				txtNameNotOk.Visibility = Visibility.Collapsed;
			}
			else
			{
				_agentNameOk = false;
				txtNameOk.Visibility = Visibility.Collapsed;
				txtNameNotOk.Visibility = Visibility.Visible;
			}
		}

		private void TxtAgentNameTextChanged(object sender, TextChangedEventArgs e)
		{
			_agentNameOk = false;
			txtNameOk.Visibility = Visibility.Collapsed;
			txtNameNotOk.Visibility = Visibility.Collapsed;
			Regex agentNameRegex = new Regex(@"\A(?<name>\S{4,16})\Z");
			if (!agentNameRegex.IsMatch(txtAgentName.Text))
			{
				txtNameOk.Visibility = Visibility.Collapsed;
				txtNameNotOk.Visibility = Visibility.Visible;
			}
		}

		private void TxtPasswordInput1PasswordChanged(object sender, RoutedEventArgs e)
		{
			if (CheckPassword())
			{
				txtPassword1Ok.Visibility = Visibility.Visible;
				txtPassword1NotOk.Visibility = Visibility.Collapsed;
			}
			else
			{
				txtPassword1Ok.Visibility = Visibility.Collapsed;
				txtPassword1NotOk.Visibility = Visibility.Visible;
			}
			if (txtPasswordInput2.Password != txtPasswordInput1.Password)
			{
				btnNext.IsEnabled = false;
			}
		}

		private void TxtPasswordInput2PasswordChanged(object sender, RoutedEventArgs e)
		{
			if (CheckPassword() && txtPasswordInput2.Password == txtPasswordInput1.Password && _agentNameOk)
				btnNext.IsEnabled = true;
			else
				btnNext.IsEnabled = false;
		}

		private bool CheckPassword()
		{
			string pwd1 = txtPasswordInput1.Password;
			//string pwd2 = txtPasswordInput2.Password;

			if (string.IsNullOrEmpty(pwd1))
				return false;

			Regex passwordRegex = new Regex(@"^.*(?=.{8,})(?=.{2,}\d)(?=.{3,}[a-z])(?=.{4,}[A-Z]).*$");
			if (!passwordRegex.IsMatch(pwd1))
				return false;
			return true;
		}

		private void TxtPasswordInput1GotFocus(object sender, RoutedEventArgs e)
		{
			txtPasswordInput1.SelectAll();
		}

		private void TxtPasswordInput2GotFocus(object sender, RoutedEventArgs e)
		{
			txtPasswordInput2.SelectAll();
		}

		private void ClientSaveAgentNameAndPasswordCompleted(object sender, SaveAgentNameAndPasswordCompletedEventArgs e)
		{
			_client.SaveAgentNameAndPasswordCompleted -= ClientSaveAgentNameAndPasswordCompleted;
			if (e.Result)
			{
				_currentState++;
				SwitchState();
			}
			else
			{
				MessageBox.Show("Error creating your agent. Please contact support.");
				_currentState--;
				SwitchState();
			}
		}

		#endregion
	}
}

namespace UserRegistration.RegSvc
{
	public partial class Corporation
	{
		public override string ToString()
		{
			return string.Format("{0} {1}", Name, TopLevelDomain.Name);
		}
	}
}